﻿#ifndef WORDCLOUNDMANAGER_H
#define WORDCLOUNDMANAGER_H

#include <QObject>
#include <QPoint>
#include <QFont>
#include <QtMath>
#include <QRect>
#include <QVector>
#include <QVector2D>
#include <QVector3D>
#include <QPainter>
#include <QJsonObject>
#include <QFontMetrics>
#include <qdebug.h>
#include <QTime>

class WordCloundManager : public QObject
{
    Q_OBJECT
public:
    explicit WordCloundManager(QObject *parent = nullptr);
public:
    /**
     * 获取画布的中心点坐标
     @method getCenterPoint
     @param {HTMLDOMElement} DOMElement 通常是一个div
     @return {array} [x, y] 包含中心点坐标的数组
     */
    static QPoint getCenterPoint(const QRect &wholeRect){
        QRect rect = wholeRect;
        int rectTop = rect.y();
        int rectLeft = rect.x();
        int ngx = qCeil(rectLeft + rect.width());
        int ngy = qCeil(rectTop + rect.height());
        QPoint center = QPoint((ngx / 2) + rectLeft, (ngy / 2) + rectTop);
        return center;
    }
    // 获取最大半径
    static int getMaxRadius(const QRect & wholeRect,int cellSpace=1){
        QRect rect = wholeRect;
        int ngx = qCeil(rect.width() / cellSpace);
        int ngy = qCeil(rect.height() / cellSpace);
        int maxRadius = qFloor(qSqrt(ngx * ngx + ngy * ngy));
        return maxRadius;
    }
    /**
      * 获取圆上每个点的坐标
      @method getCenterPoint
      @param {int} radius 半径
      @param {array} center 类似[11,22]中心点
      @param {int} offsetY y坐标的偏移位置，默认为1
      @return {array} [x, y] 圆上坐标的数组
      */
    static QList<QVector2D> getPointsAtRadius(int radius, QPoint center ,double offsetY2=1, int multiple2=30){
        // 因为像素是一个正方形，一个正方形的四周有8块正方形可包围。
        double T = radius * 8;
        double t = T;
        QList<QVector2D> points;
        double offsetY = offsetY2;
        int multiple = multiple2;

        if (radius == 0) {
            points.append( QVector2D(QPoint(center.x(), center.y())));
        }
        while (t) {
            // 参考http://www.cnblogs.com/xieon1986/archive/2013/01/28/2880367.html
            // 圆上每个点的
            // Y坐标=圆心y坐标 + Math.sin(2*Math.PI / 360) * 半径
            // X坐标=圆心x坐标 + Math.cos(2*Math.PI / 360) * 半径
            // 弧度=(2*PI/360)*角度
            // 基于圆心的x坐标 X坐标=圆心x坐标 + Math.sin((2*Math.PI / 360) * 1) * 半径
            // 这里的T同360°的意义 类型转换 不然相乘得到0
            double f = (double)(t/T);
            double sin = (double)(qSin( ( 2.0 * M_PI *f )) *offsetY);
            double cos = (double)(qCos( ( 2.0 * M_PI *f )) *offsetY);
            QVector2D d(
                        QPoint(
                            center.x() + (radius*multiple) * cos,
                            center.y() + (radius*multiple) * sin)
                        );
            points.append(d);
            t = t - 1;
        }
        return points;
    }

    //获取随机颜色的值
    static QColor getRandomColor(){
        QList<QString> arr = QList<QString>{"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
        QString color = "#";
        qsrand(QTime::currentTime().msec());
        for(int i=0;i<6;i++){
            int rd = qrand()%16;
            QString c =QString::number(rd);
            c = arr[rd];
            color = color + c;
        }
        return QColor(color);
    }
    // 获取随机文字的大小
    static int getRandomFontSize(){
        QList<int> arr = QList<int>{28,30,34,40};
        QVector<int> res;
        qsrand(QTime::currentTime().msec());
        for (int i = 0, len = arr.length(); i < len; i++) {
            int j = qFloor(qrand() % arr.length());
            //
            res.append(arr[j]);
            arr.removeAt(j);
        }
        qDebug()<<Q_FUNC_INFO<<res[0];
        return res[0];
    }
    /**
     * 获取文本的宽高
     @method getCenterPoint
     @param {HTMLDOMElement} DOMElement 通常是一个div
     @return {array} [x, y] 包含中心点坐标的数组
     */
    static QJsonObject getTextInfo(const QString &word,QJsonObject userCSS){
        int fontSize = getRandomFontSize();
        if(!userCSS.isEmpty()){
            fontSize = userCSS.value("fontsize").toInt();
        }
        QFont f;
        f.setPointSize(fontSize);
        f.setFamily(QStringLiteral("微软雅黑"));
        QFontMetrics fontM(f);
        int fw = fontM.boundingRect(word).width();
        // 通过字体大小获取高度
        int fh = fontM.height();
        QJsonObject obj;
        obj.insert("width",(fw));
        obj.insert("height",(fh));
        obj.insert("word",word);
        obj.insert("fontsize",fontSize);
        return obj;
    }
    static void  drawText(QPoint position,const QJsonObject& textInfo, QPainter *p ){
        p->setPen(getRandomColor());
        p->setFont(QFont(QStringLiteral("微软雅黑"),textInfo.value("fontsize").toInt()));
        qDebug()<<"postion:"<<position<<" font size: "<<p->font().pointSizeF()
               <<" text "<<textInfo.value("word").toString();
        QRect f;
        f.setTopLeft(position);
        f.setWidth(textInfo.value("width").toInt());
        f.setHeight(textInfo.value("height").toInt());
        p->drawText(position,textInfo.value("word").toString());
    }
    /**
     * 获取文本的左上右下坐标，
     @param {array} topLeft 类似
     @return {object} textInfo 包含中心点坐标的数组
     */
    static QList<QVector2D > getTopLeft(QVector2D topLeft, QVector2D textInfo){
        int left1 = topLeft.x();
        int top1 = topLeft.y();

        QList<QVector2D > arrayV;
        QVector2D tempVector,tem2;

        tempVector.setX(left1);
        tempVector.setY(top1);

        tem2.setX(left1+ textInfo.x());
        tem2.setY(top1 + textInfo.y());

        arrayV.append(tempVector);
        arrayV.append(tem2);
        return arrayV;
    }

    /**
     * 判断两个矩形是否相交
     * 参考：http://www.cnblogs.com/avril/archive/2012/11/13/2767577.html
     * http://www.cnblogs.com/avril/archive/2013/04/01/2993875.html
     @method isCorssRect
     @param {array}
     @param {array}
     @return {bool} true表示有重叠，false表示没有重叠
     */
    static bool isCorssRect(QList<QVector2D > array1, QList<QVector2D > array2){

        int Xa1 = array1.at(0).toPoint().x();
        int Ya1 = array1.at(0).toPoint().y();

        int Xa2 = array1.at(1).toPoint().x();
        int Ya2 = array1.at(1).toPoint().y();

        int Xb1 = array2.at(0).toPoint().x();
        int Yb1 = array2.at(0).toPoint().y();

        int Xb2 = array2.at(1).toPoint().x();
        int Yb2 = array2.at(1).toPoint().y();


        int Xc1 = qMax(Xa1,Xb1);
        int Yc1 = qMax(Ya1,Yb1);
        int Xc2 = qMin(Xa2,Xb2);
        int Yc2 = qMin(Ya2,Yb2);

        return (Xc1 <= Xc2 && Yc1 <= Yc2);
    }

    // 获取可安置的坐标
    static QVector2D getDrawPosition(QJsonObject textInfo, int maxRadius, QPoint center,int cellSpace1 ,QList< QList<QVector2D> >  &drawArray){
        int textInfo_width = textInfo.value("width").toInt();
        int textInfo_height = textInfo.value("height").toInt();
        qDebug()<<"getDrawPosition center"<<maxRadius;
        int cellSpace = cellSpace1;
        QVector2D wh;
        wh.setX(textInfo_width);
        wh.setY(textInfo_height);
        for(int i=0; i < maxRadius; i++){
            QList<QVector2D> points = getPointsAtRadius(i, center, 0.64, cellSpace);
            QVector2D v2d = getunCrossPostion(drawArray,points,wh);
            if(v2d.isNull()){
                continue;
            }else{
                return v2d;
            }
        }
        return QVector2D();
    }

    static QVector2D getunCrossPostion(QList< QList<QVector2D> >  &drawArray,const QList<QVector2D>& points
                                ,const QVector2D& wh){
        for( int j=0; j<points.length(); j++){
            QList<QVector2D> topLeft = getTopLeft(points[j],wh);
            // 是否和已存的文字碰撞
            //qDebug()<<Q_FUNC_INFO<<textInfo.value("word").toString()<<" x "<<points[j].x()<<" y: "<<points[j].y();
//            qDebug()<<QStringLiteral("继续检测..J:.")<<j;
            bool iscross = false;
            for( int z =0 ; z< drawArray.length(); z++){
                if(isCorssRect(topLeft, drawArray[z])){
                    //qDebug()<<QStringLiteral("重新检测===jjj===")<<j<<" drawArray size: "<<drawArray.length();
                    iscross = true;
                    break;
                }
            }
            if(!iscross){
                drawArray.append(topLeft);
                qDebug()<<"get the corrent postion: "<<points[j]<<" j:"<<j<<" drawArray data size: "<<drawArray.length();
                return points[j];
            }
        }
        return QVector2D();
    }
};

#endif // WORDCLOUNDMANAGER_H
